vue.js推荐使用的扩展名为vue的组件模板,可以让标签的属性和内容都变得动态,这是很强大也很已用的能力。但是,如果我需要标签名本身都是可以动态的话,怎么办?

比如我希望提供一个标签,可以根据属性值动态选择head的层级,像是把

<h1>header1</h1>
<h2>header2</h2>  

可以替代为:

   <hdr :level="1">header1</hdr>
   <hdr :level="2">header2</hdr>

答案就是render函数。具体做法就是首先注册一个组件:

Vue.component('hdr', {
  render: function (createElement) {
    return createElement(
      'h' + this.level,   // tag name
      this.$slots.default // array of children
    )
  },
  props: {
    level: {
      type: Number,
      required: true
    }
  }
})

随后在html内使用此组件:

//javascript
new Vue({
  el: '#example'
})

// html
<div id="example">
   <hdr :level="1">abc</hdr>
   <hdr :level="2">abc</hdr>
</div>

可以执行的代码在此:

http://jsbin.com/xesihujuda/1...

函数render会传入一个createElement函数作为参数,你可以使用此函数来创建标签。第一个参数就是标签名称,以及为创建的标签提供属性和内容,以及创建子标签。在render函数内,可以通过this.$slots访问slot,从而把slot内的元素插入到当前被创建的标签内。为了方便,完整的使用createElement的实例代码抄写自vue.js手册。如下 :

createElement(
  // {String | Object | Function}
  // An HTML tag name, component options, or function
  // returning one of these. Required.
  'div',
  // {Object}
  // A data object corresponding to the attributes
  // you would use in a template. Optional.
  {
    // (see details in the next section below)
  },
  // {String | Array}
  // Children VNodes. Optional.
  [
    createElement('h1', 'hello world'),
    createElement(MyComponent, {
      props: {
        someProp: 'foo'
      }
    }),
    'bar'
  ]
)

本来使用render的理由,就是我在封装bootstrap carousel的过程中产生的需要,如下代码是一个封装carousel的实际案例:

javascript

function img1(createElement,s){
  return createElement('img',{attrs:{src:'https://placehold.it/'+s}})
} 

function item(createElement,isa,s){
  return createElement('div',
      {'class':{'item':true,'active':isa}},
    [
      img1(createElement,s)
    ])
}

function inner(createElement){
  return createElement('div',{'class':{'carousel-inner':true}},[
      item(createElement,true,'103X100')
    ,item(createElement,false,'101X100')
    ,item(createElement,false,'102X100')
    ])
}
function leftcontrol(createElement){
     return createElement('a',
          {
         attrs:{
           'href':'#myCarousel1',
           'data-slide':'prev',
           'class':'carousel-control left'}
       },
    [
      left(createElement)
    ])
}
function rightcontrol(createElement){
     return createElement('a',
          {
         attrs:{
           'href':'#myCarousel',
           'data-slide':'prev',
           'class':'carousel-control right'}
       },
    [
      right(createElement)
    ])
}

function right(createElement){
     return createElement('span',
          {
         attrs:{
           'class':'glyphicon glyphicon-chevron-right'}
       },
    [])
}
function left(createElement){
     return createElement('span',
          {
         attrs:{
           'class':'glyphicon glyphicon-chevron-left'}
       },
    [])
}


Vue.component('mmm', {
  render: function (createElement) {
   return createElement('div',
        {
            //'class':{'carousel':true, 'slide':true},
            attrs:{
                id:'myCarousel1',
              'class':'carousel slide',
              'data-ride':'carousel'

            }
        },
               [inner(createElement),
        leftcontrol(createElement),
         rightcontrol(createElement)]
   )      
  }
})   
new Vue({
  el: '#example'
})

html

<div id="example">
   <mmm></mmm>
</div>

可执行案例

http://jsbin.com/pulohup/edit...

参考

https://vuejs.org/guide/rende...


Reco
4.6k 声望541 粉丝

敢作敢为